package com.pingpang.websocketchat;

import java.net.InetSocketAddress;
import java.util.Set;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;

/** 
 * 处理TextWebSocketFrame
 */
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

	// public static ChannelGroup channels = new
	// DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
	private int count=0;
	private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled
			.unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat",
					CharsetUtil.UTF_8));  
	
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { // (1)
		InetSocketAddress ipSocket = (InetSocketAddress)ctx.channel().remoteAddress();
	     String clientIp = ipSocket.getAddress().getHostAddress();
	     System.out.println("客户端ip地址："+clientIp);
		
		if("ping".equals(msg.text())) {
			ctx.channel().writeAndFlush(new TextWebSocketFrame("pong"));
			return;
		}
		
		if("Heartbeat".equals(msg.text())) {
			count=0;
			return;	
		}
		
		ObjectMapper mapper = new ObjectMapper();
		Message message = mapper.readValue(msg.text(), Message.class);

		Channel incoming = ctx.channel();
		if (null != message) {
			
			//这里添加用户数据校验
			if(!ChatType.BIND.equals(message.getCmd())) {
				if(!incoming.equals(ChannelManager.getChannel(message.getFrom().getUserCode()))) {
					System.out.println("非登录用户操作:"+message.toString());
					return;
				}
			}
			
			switch (message.getCmd()) {
			case ChatType.BIND:
				ChannelManager.addChannel(message.getFrom(), incoming);
				break;
			case ChatType.LEAVE:
				ChannelManager.removeChannelByCode(message.getFrom().getUserCode());
				break;
			case ChatType.SINGLE:
				// message.setMsg(HtmlUtils.htmlEscape(message.getMsg()));
				if (null != ChannelManager.getChannel(message.getAccept().getUserCode())) {
					message.setFrom(ChannelManager.getChartUser(message.getFrom().getUserCode()));
					message.setAccept(ChannelManager.getChartUser(message.getAccept().getUserCode()));
					ChannelManager.getChannel(message.getAccept().getUserCode())
							.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
				} else {
					ChartUser from = message.getFrom();
					message.setFrom(message.getAccept());
					message.setAccept(from);
					message.setMsg("[" + message.getFrom() + "]未上线");
					incoming.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
				}
				break;
			case ChatType.GROUP:
				
				message.setFrom(ChannelManager.getChartUser(message.getFrom().getUserCode()));

				if (!ChannelManager.isExit(message.getGroup(), message.getFrom().getUserCode())) {
					ChannelManager.addGroup(message.getGroup(), message.getFrom());
				}
				Set<ChartUser> user = ChannelManager.getGroupUser(message.getGroup());
				for (ChartUser str : user) {
					if (!str.equals(message.getFrom())) {
						ChannelManager.getChannel(str.getUserCode())
								.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
					}
				}
				break;
			case ChatType.QUERY_USER:
				message.setChatSet(ChannelManager.getAllUser());
				System.out.println("当前用户数量:"+message.getChatSet().size());
				incoming.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
				break;
			default:
				System.out.println("未识别的命令");
				break;
			}
		}
		/*
		 * for (Channel channel : channels) { if (channel != incoming){
		 * channel.writeAndFlush(new TextWebSocketFrame("[" + incoming.remoteAddress() +
		 * "]" + msg.text())); } else { channel.writeAndFlush(new
		 * TextWebSocketFrame("[you]" + msg.text() )); } }
		 */
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent event = (IdleStateEvent) evt;
			System.out.println(ctx.channel().remoteAddress()+"超时次数:"+count);
			String type = "";
			if (event.state() == IdleState.READER_IDLE) {
				type = "read idle";
				count++;
				if(count>5) {
					  System.out.println("超时次数达到最大值了，断开连接");
		              ChannelManager.removeChannelByChannel(ctx.channel());
		              ctx.channel().close();
					}
			} else if (event.state() == IdleState.WRITER_IDLE) {
				type = "write idle";
				count=0;
			} else if (event.state() == IdleState.ALL_IDLE) {
				type = "all idle";
				count=0;
			}
			ctx.writeAndFlush(new TextWebSocketFrame("Heartbeat")).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
			System.out.println( ctx.channel().remoteAddress()+"超时类型：" + type);
		}
		super.userEventTriggered(ctx, evt);
	}
	
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // (2)
		Channel incoming = ctx.channel();
		// Broadcast a message to multiple Channels
		// channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " +
		// incoming.remoteAddress() + " 加入"));

		// channels.add(incoming);
		System.out.println("Client:" + incoming.remoteAddress() + "加入");
	}

	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // (3)
		Channel incoming = ctx.channel();

		// Broadcast a message to multiple Channels
		// channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " +
		// incoming.remoteAddress() + " 离开"));

		System.out.println("Client:" + incoming.remoteAddress() + "离开");
		ChannelManager.removeChannelByChannel(incoming);
		// A closed Channel is automatically removed from ChannelGroup,
		// so there is no need to do "channels.remove(ctx.channel());"
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
		Channel incoming = ctx.channel();
		System.out.println("Client:" + incoming.remoteAddress() + "在线");
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
		Channel incoming = ctx.channel();
		System.out.println("Client:" + incoming.remoteAddress() + "掉线");
		ChannelManager.removeChannelByChannel(incoming);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) // (7)
			throws Exception {
		Channel incoming = ctx.channel();
		System.out.println("Client:" + incoming.remoteAddress() + "异常");
		// 当出现异常就关闭连接
		cause.printStackTrace();
		ctx.close();
	}

}
